package IntelIpps

/*
#cgo CFLAGS: -ID:/DevelopTools/IPPS2022/ipp/2021.12/include
#cgo LDFLAGS: -LD:/DevelopTools/IPPS2022/ipp/2021.12/lib -lipps -lippcore
#include <ipp.h>
#include <stdlib.h>
*/
import "C"
import (
	"unsafe"
)

type IppImpl struct {
	// FFT 状态
	sizeSpec, sizeInit, sizeBuffer C.int
}

// 全局变量
var IPP = &IppImpl{}

// SortFloat
func (i *IppImpl) SortFloat(in []float32, ascend bool) []float32 {
	out := make([]float32, len(in))
	copy(out, in)
	ptr := (*C.Ipp32f)(unsafe.Pointer(&out[0]))
	lenC := C.int(len(in))
	var status C.IppStatus
	if ascend {
		status = C.ippsSortAscend_32f_I(ptr, lenC)
	} else {
		status = C.ippsSortDescend_32f_I(ptr, lenC)
	}
	if status != C.ippStsNoErr {
		return in // fallback
	}
	return out
}

// NormalizeFloat
func (i *IppImpl) NormalizeFloat(in []float32, sub, div float32) []float32 {
	out := make([]float32, len(in))
	status := C.ippsNormalize_32f(
		(*C.Ipp32f)(unsafe.Pointer(&in[0])),
		(*C.Ipp32f)(unsafe.Pointer(&out[0])),
		C.int(len(in)),
		C.Ipp32f(sub),
		C.Ipp32f(div),
	)
	if status != C.ippStsNoErr {
		return in
	}
	return out
}

// DotProductFloat
func (i *IppImpl) DotProductFloat(a, b []float32) float32 {
	var result C.Ipp32f
	C.ippsDotProd_32f(
		(*C.Ipp32f)(unsafe.Pointer(&a[0])),
		(*C.Ipp32f)(unsafe.Pointer(&b[0])),
		C.int(len(a)),
		&result,
	)
	return float32(result)
}

// MulCFloat
func (i *IppImpl) MulCFloat(in []float32, c float32) []float32 {
	out := make([]float32, len(in))
	C.ippsMulC_32f(
		(*C.Ipp32f)(unsafe.Pointer(&in[0])),
		C.Ipp32f(c),
		(*C.Ipp32f)(unsafe.Pointer(&out[0])),
		C.int(len(in)),
	)
	return out
}

// MulFloat
func (i *IppImpl) MulFloat(a, b []float32) []float32 {
	out := make([]float32, len(a))
	C.ippsMul_32f(
		(*C.Ipp32f)(unsafe.Pointer(&a[0])),
		(*C.Ipp32f)(unsafe.Pointer(&b[0])),
		(*C.Ipp32f)(unsafe.Pointer(&out[0])),
		C.int(len(a)),
	)
	return out
}

// AddFloat
func (i *IppImpl) AddFloat(a, b []float32) []float32 {
	if len(a) != len(b) {
		return nil
	}
	out := make([]float32, len(a))
	status := C.ippsAdd_32f(
		(*C.Ipp32f)(unsafe.Pointer(&a[0])),
		(*C.Ipp32f)(unsafe.Pointer(&b[0])),
		(*C.Ipp32f)(unsafe.Pointer(&out[0])),
		C.int(len(a)),
	)
	if status != C.ippStsNoErr {
		return nil
	}
	return out
}

// SubFloat
func (i *IppImpl) SubFloat(a, b []float32) []float32 {
	if len(a) != len(b) {
		return nil
	}
	out := make([]float32, len(a))
	status := C.ippsSub_32f(
		(*C.Ipp32f)(unsafe.Pointer(&a[0])),
		(*C.Ipp32f)(unsafe.Pointer(&b[0])),
		(*C.Ipp32f)(unsafe.Pointer(&out[0])),
		C.int(len(a)),
	)
	if status != C.ippStsNoErr {
		return nil
	}
	return out
}

// SumFloat
func (i *IppImpl) SumFloat(in []float32, hint HintAlgorithm) float32 {
	var result C.Ipp32f
	h := C.IppHintAlgorithm(hint)
	C.ippsSum_32f(
		(*C.Ipp32f)(unsafe.Pointer(&in[0])),
		C.int(len(in)),
		&result,
		h,
	)
	return float32(result)
}

// MaxFloat
func (i *IppImpl) MaxFloat(in []float32) float32 {
	var result C.Ipp32f
	C.ippsMax_32f(
		(*C.Ipp32f)(unsafe.Pointer(&in[0])),
		C.int(len(in)),
		&result,
	)
	return float32(result)
}

// MinFloat
func (i *IppImpl) MinFloat(in []float32) float32 {
	var result C.Ipp32f
	C.ippsMin_32f(
		(*C.Ipp32f)(unsafe.Pointer(&in[0])),
		C.int(len(in)),
		&result,
	)
	return float32(result)
}

// MeanFloat
func (i *IppImpl) MeanFloat(in []float32) float32 {
	var result C.Ipp32f
	C.ippsMean_32f(
		(*C.Ipp32f)(unsafe.Pointer(&in[0])),
		C.int(len(in)),
		&result,
		C.ippAlgHintFast,
	)
	return float32(result)
}

// NormInfFloat
func (i *IppImpl) NormInfFloat(in []float32) float32 {
	var result C.Ipp32f
	C.ippsNorm_Inf_32f(
		(*C.Ipp32f)(unsafe.Pointer(&in[0])),
		C.int(len(in)),
		&result,
	)
	return float32(result)
}
